package com.uuah.server.component;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.uuah.api.lifecycle.IDisposable;
import com.uuah.api.lifecycle.IStartable;
import com.uuah.api.lifecycle.IStoppable;
import com.uuah.api.lifecycle.Initialisable;
import com.uuah.exception.AbstractUuahException;
import com.uuah.exception.UuahException;
import com.uuah.exception.lifecycle.InitialisationException;
import com.uuah.server.UuahEventContext;
import com.uuah.server.api.IUuahEvent;
import com.uuah.server.api.IUuahEventContext;
import com.uuah.server.api.component.IComponent;
import com.uuah.server.api.component.ILifecycleAdapter;
import com.uuah.server.api.component.model.IEntryPointResolverSet;
import com.uuah.server.component.model.resolvers.DefaultEntryPointResolverSet;
import com.uuah.server.config.i18n.ServerMessages;
import com.uuah.server.exception.AbstractUuahServerException;
import com.uuah.server.exception.service.ServiceException;
import com.uuah.server.transport.RequestContextHelper;

/**
 * <code>DefaultLifecycleAdapter</code> provides lifecycle methods for all Uuah
 * managed components. It's possible to plugin custom lifecycle adapters, this
 * can provide additional lifecycle methods triggered by an external source.
 *
 * <p>update record:updator，update time，update content and version</p>
 * @author <a href="jonny_quan@hotmail.com">jonny</a>
 * @date 2009 2009-3-27 上午09:47:18
 * @version 1.0.0
 */
public class LifecycleAdapter implements ILifecycleAdapter {
	protected transient final Logger logger = LoggerFactory
			.getLogger(LifecycleAdapter.class);

	protected Object componentObject;
	protected IComponent component;
	private boolean isStoppable = false;
	private boolean isStartable = false;
	private boolean isDisposable = false;

	private boolean started = false;
	private boolean disposed = false;

	private IEntryPointResolverSet entryPointResolver;

	public LifecycleAdapter(Object componentObject, IComponent component)
			throws AbstractUuahException {
		this(componentObject, component, new DefaultEntryPointResolverSet());
	}

	public LifecycleAdapter(Object componentObject, IComponent component,
			IEntryPointResolverSet entryPointResolver)
			throws AbstractUuahServerException {

		if (componentObject == null) {
			throw new IllegalArgumentException("POJO Service cannot be null");
		}
		if (entryPointResolver == null) {
			entryPointResolver = new DefaultEntryPointResolverSet();
		}
		this.componentObject = componentObject;
		this.component = component;
		this.entryPointResolver = entryPointResolver;

		isStartable = IStartable.class.isInstance(componentObject);
		isStoppable = IStoppable.class.isInstance(componentObject);
		isDisposable = IDisposable.class.isInstance(componentObject);
	}

	public void start() throws AbstractUuahException {
		if (isStartable) {
			try {
				((IStartable) componentObject).start();
				started = true;
			} catch (Exception e) {
				throw new UuahException(ServerMessages
						.failedToStart("Uuah Service: "
								+ component.getService().getName()), e);
			}
		} else {
			started = true;
		}
	}

	public void stop() throws AbstractUuahException {
		if (isStoppable) {
			try {
				((IStoppable) componentObject).stop();
				started = false;
			} catch (Exception e) {
				throw new UuahException(ServerMessages
						.failedToStop("UMO Service: "
								+ component.getService().getName()), e);
			}
		} else {
			started = false;
		}
	}

	public void dispose() {
		if (isDisposable) {
			try {
				((IDisposable) componentObject).dispose();
			} catch (Exception e) {
				logger.error("failed to dispose: "
						+ component.getService().getName(), e);
			}
		}
		disposed = true;
	}

	public boolean isStarted() {
		return started;
	}

	public boolean isDisposed() {
		return disposed;
	}

	public Object invoke(IUuahEvent event) throws AbstractUuahServerException {
		IUuahEventContext eventContext = new UuahEventContext(event);
		Object result;
		try {
			if (component.getEntryPointResolverSet() != null) {
				result = component.getEntryPointResolverSet().invoke(
						componentObject, eventContext);
			} else {
				result = entryPointResolver.invoke(componentObject,
						eventContext);
			}
		} catch (Exception e) {
			throw new ServiceException(RequestContextHelper.getEventContext()
					.getMessage(), component.getService(), e);
		}

		return result;
	}

	public void initialise() throws InitialisationException {
		if (Initialisable.class.isInstance(componentObject)) {
			((Initialisable) componentObject).initialise();
		}
	}
}
